/*******************************************************************************
*	                           bsp ram clear.c
*******************************************************************************/
#include "bsp.h"
#include "bsp_qpi_opt.h"
#include "pincfg.h"

static qspi_cmd_type qpi_cmd_cfg;
#define cmd_cfg qpi_cmd_cfg
#define QPIX QSPI1

/*****************************************************************************
* @brief   hal init.
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void bsp_qpi_init(void)
{
	intx_alloc();

	intx_disable();
	
	/* enable the qspi clock */
	crm_periph_clock_enable(CRM_QSPI1_PERIPH_CLOCK, TRUE);
	crm_periph_reset(CRM_QSPI1_PERIPH_RESET, TRUE);
	crm_periph_reset(CRM_QSPI1_PERIPH_RESET, FALSE);
	
	intx_enable();

	/* switch to cmd port */
	qspi_xip_enable(QPIX, FALSE);

	/* set sclk , AHB / 4*/
	qspi_clk_division_set(QPIX, QSPI_CLK_DIV_4);

	/* set sck idle mode 0 */
	qspi_sck_mode_set(QPIX, QSPI_SCK_MODE_0);

	/* set wip in bit 0 */
	qspi_busy_config(QPIX, QSPI_BUSY_OFFSET_0);

	cmd_cfg.pe_mode_enable = FALSE;
	cmd_cfg.pe_mode_operate_code = 0;
	cmd_cfg.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	cmd_cfg.read_status_config = QSPI_RSTSC_HW_AUTO;
	cmd_cfg.read_status_enable = FALSE;
}

/*****************************************************************************
* @brief   cmd exe.
* @return  none
*****************************************************************************/
void bsp_qpi_opt_mode(qspi_operate_mode_type opt_mode)
{
	cmd_cfg.operation_mode = opt_mode;
}

/*****************************************************************************
* @brief   cmd exe.
* @return  none
*****************************************************************************/
void bsp_qpi_cmd_exe(uint8_t cmd)
{
	/* command config */
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = 0;
	cmd_cfg.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	cmd_cfg.data_counter = 0;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = TRUE;

	/* command exe */
	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);
}

/*****************************************************************************
* @brief   cmd set.
* @return  none
*****************************************************************************/
void bsp_qpi_cmd_set(uint8_t cmd, uint8_t par)
{
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = 0;
	cmd_cfg.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	cmd_cfg.data_counter = 1;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = TRUE;

	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	while (qspi_flag_get(QPIX, QSPI_TXFIFORDY_FLAG) == RESET)
		;
	qspi_byte_write(QPIX, par);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);
}

/*****************************************************************************
* @brief   cmd get.
* @return  none
*****************************************************************************/
uint8_t bsp_qpi_cmd_get(uint8_t cmd)
{
	uint8_t data;

	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = 0;
	cmd_cfg.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	cmd_cfg.data_counter = 1;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = FALSE;

	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	while (qspi_flag_get(QPIX, QSPI_RXFIFORDY_FLAG) == RESET)
		;
	data = qspi_byte_read(QPIX);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);

	return data;
}

/*****************************************************************************
* @brief   cmd set.
* @return  none
*****************************************************************************/
void bsp_qpi_cmd_aset(uint8_t cmd, uint8_t addr, uint8_t par)
{
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = addr;
	cmd_cfg.address_length = QSPI_CMD_ADRLEN_1_BYTE;
	cmd_cfg.data_counter = 1;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = TRUE;

	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	while (qspi_flag_get(QPIX, QSPI_TXFIFORDY_FLAG) == RESET)
		;
	qspi_byte_write(QPIX, par);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);
}

/*****************************************************************************
* @brief   cmd get.
* @return  none
*****************************************************************************/
uint8_t bsp_qpi_cmd_aget(uint8_t cmd, uint8_t addr)
{
	uint8_t data;

	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = addr;
	cmd_cfg.address_length = QSPI_CMD_ADRLEN_1_BYTE;
	cmd_cfg.data_counter = 1;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = FALSE;

	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	while (qspi_flag_get(QPIX, QSPI_RXFIFORDY_FLAG) == RESET)
		;

	data = qspi_byte_read(QPIX);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);

	return data;
}

/*****************************************************************************
* @brief   cmd auto.
* @return  none
*****************************************************************************/
void bsp_qpi_cmd_multi_read(
	uint8_t cmd,
	uint32_t addr, qspi_cmd_adrlen_type addr_len,
	uint8_t *buff, uint8_t len)
{
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = addr;
	cmd_cfg.address_length = addr_len;
	cmd_cfg.data_counter = len;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = FALSE;

	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	while (qspi_flag_get(QPIX, QSPI_RXFIFORDY_FLAG) == RESET)
		;
	while (len--)
		*buff++ = qspi_byte_read(QPIX);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);
}

/*****************************************************************************
* @brief   cmd auto.
* @return  none
*****************************************************************************/
void bsp_qpi_cmd_multi_write(
	uint8_t cmd,
	uint32_t addr, qspi_cmd_adrlen_type addr_len,
	const uint8_t *buff, uint8_t len)
{
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = addr;
	cmd_cfg.address_length = addr_len;
	cmd_cfg.data_counter = len;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = TRUE;

	qspi_cmd_operation_kick(QPIX, &cmd_cfg);
	while (qspi_flag_get(QPIX, QSPI_TXFIFORDY_FLAG) == RESET)
		;
	while (len--)
		qspi_byte_write(QPIX, *buff++);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);
}

/**
  * @brief  qspi dma set
  * @param  dir: dma transfer direction
  * @param  buf: the pointer for dma data
  * @param  length: data length
  * @retval none
  */
void qspi_dma_set(dma_dir_type dir, uint8_t *buf, uint32_t length)
{
	dma_init_type dma_init_struct;
	dma_reset(DMA2_CHANNEL1);
	dma_default_para_init(&dma_init_struct);
	dma_init_struct.buffer_size = (length + 3) >> 2; /* using word unit */
	dma_init_struct.loop_mode_enable = FALSE;
	dma_init_struct.direction = dir;
	dma_init_struct.memory_base_addr = (uint32_t)buf;
	dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD;
	dma_init_struct.memory_inc_enable = TRUE;
	dma_init_struct.peripheral_base_addr = (uint32_t)(&(QPIX->dt));
	dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD;
	dma_init_struct.peripheral_inc_enable = FALSE;
	dma_init_struct.priority = DMA_PRIORITY_HIGH;

	dma_init(DMA2_CHANNEL1, &dma_init_struct);

	dmamux_init(DMA2MUX_CHANNEL1, DMAMUX_DMAREQ_ID_QSPI1);
	dmamux_enable(DMA2, TRUE);

	dma_channel_enable(DMA2_CHANNEL1, TRUE);
}

/*****************************************************************************
* @brief   addr read.
* @return  none
*****************************************************************************/
void bsp_qpi_addr_read(
	uint8_t cmd,
	uint32_t addr, qspi_cmd_adrlen_type addr_len,
	uint8_t dummy,
	uint8_t *buf, uint16_t total_len)
{
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = addr;
	cmd_cfg.address_length = addr_len;
	cmd_cfg.data_counter = total_len;
	cmd_cfg.second_dummy_cycle_num = dummy;
	cmd_cfg.write_data_enable = FALSE;

	/* config qspi's dma mode */
	qspi_dma_enable(QPIX, TRUE);
	qspi_dma_rx_threshold_set(QPIX, QSPI_DMA_FIFO_THOD_WORD08);

	/* config and enable dma */
	qspi_dma_set(DMA_DIR_PERIPHERAL_TO_MEMORY, buf, total_len);

	/* kick command */
	qspi_cmd_operation_kick(QPIX, &cmd_cfg);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);

	/* wait dma completed */
	while (dma_flag_get(DMA2_FDT1_FLAG) == RESET)
		;
	dma_flag_clear(DMA2_FDT1_FLAG);
	qspi_dma_enable(QPIX, FALSE);
}

/*****************************************************************************
* @brief   addr write.
* @return  none
*****************************************************************************/
void bsp_qpi_addr_write(
	uint8_t cmd,
	uint32_t addr, qspi_cmd_adrlen_type addr_len,
	const uint8_t *buf, uint16_t total_len)
{
	cmd_cfg.instruction_code = cmd;
	cmd_cfg.address_code = addr;
	cmd_cfg.address_length = addr_len;
	cmd_cfg.data_counter = total_len;
	cmd_cfg.second_dummy_cycle_num = 0;
	cmd_cfg.write_data_enable = TRUE;

	/* config qspi's dma mode */
	qspi_dma_enable(QPIX, TRUE);
	qspi_dma_tx_threshold_set(QPIX, QSPI_DMA_FIFO_THOD_WORD08);

	/* config and enable dma */
	qspi_dma_set(DMA_DIR_MEMORY_TO_PERIPHERAL, (uint8_t *)buf, total_len);

	/* kick command */
	qspi_cmd_operation_kick(QPIX, &cmd_cfg);

	/* wait command completed */
	while (qspi_flag_get(QPIX, QSPI_CMDSTS_FLAG) == RESET)
		;
	qspi_flag_clear(QPIX, QSPI_CMDSTS_FLAG);

	/* wait dma completed */
	while (dma_flag_get(DMA2_FDT1_FLAG) == RESET)
		;
	dma_flag_clear(DMA2_FDT1_FLAG);
	qspi_dma_enable(QPIX, FALSE);
}
